<template>
    <div>
        <input ref="uploadRef" class="excel-upload-input" type="file" accept=".xlsx, .xls" @change="handleClick" multiple>
        <el-button :loading="loading" type="primary" @click="handleUpload">
            导入Excel
        </el-button>
    </div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { read, utils } from 'xlsx';
import type { Sheet } from 'xlsx';
import { ToCDB } from '@/utils/index.js';

interface IProps {
    // eslint-disable-next-line @typescript-eslint/ban-types
    beforeUpload?: Function;
    // eslint-disable-next-line @typescript-eslint/ban-types
    onSuccess: Function;
}

interface IGenerateData {
    header: string[];
    results: unknown[];
}

const $props = defineProps<IProps>()
const uploadRef = ref<any>();
const loading = ref<boolean>(false);
const excelData = ref<IGenerateData>({
    header: [],
    results: []
})

/**
 * 点击按钮
 */
const handleUpload = () => {
    uploadRef.value.click()
}

/**
 * 选中文件回调函数
 * @param $event 
 */
const handleClick = ($event: any) => {
    const files = $event.target.files as File[]
    if (!files.length) return
    const filesCopy: File[] = []
    for (let i = 0; i < files.length; i++) {
        filesCopy.push(files[i])
    }
    upload(filesCopy)
}

/**
 * 判断是否有上传前置钩子函数
 * @param rawFiles 文件
 */
const upload = async (rawFiles: File[]) => {
    uploadRef.value.value = null // fix can't select the same excel
    const before = $props.beforeUpload && $props.beforeUpload(rawFiles)
    if (!before) {
        return
    }
    loading.value = true
    // 解析数据获取列表和列头
    const promiseList = rawFiles.map((item: File) => readerData(item))
    const result = await Promise.all(promiseList)
    // 列表头进行去重
    const resultObj: any = {
        header: [],
        results: []
    }
    result.forEach((item: any) => {
        resultObj.results = [...resultObj.results, ...item.results]
        resultObj.header = [...resultObj.header, ...item.header]
    })
    // 全角转半角
    resultObj.results.forEach(item => {
        for(let i in item) {
            item[i] = ToCDB(String(item[i]))
        }
    })
    resultObj.header = [...new Set(resultObj.header)]
    generateData(resultObj)
    loading.value = false
    // generateData({ header, results })
}

/**
 * 读取文件数据
 * @param rawFile 文件
 */
const readerData = (rawFile: File) => {
    return new Promise((resolve) => {
        const reader = new FileReader()
        reader.onload = (e: any) => {
            const data = e.target.result
            const workbook = read(data, { type: 'array' })
            // 处理多sheet表数据
            // const firstSheetName = workbook.SheetNames[0]
            // const worksheet = workbook.Sheets[firstSheetName]
            // const header = getHeaderRow(worksheet)
            // const results = utils.sheet_to_json(worksheet)
            let header: string[] = []
            let results: any[] = []
            for (let value in workbook.Sheets) {
                if (workbook.Sheets[value]['!ref']) {
                    const h = getHeaderRow(workbook.Sheets[value])
                    const rSheet = getTableRow(workbook.Sheets[value])
                    const r = utils.sheet_to_json(rSheet)
                    header = [...new Set([...h, ...header])]
                    results = [...results, ...r]
                }
            }
            resolve({ header, results })
        }
        reader.readAsArrayBuffer(rawFile)
    })
}

/**
 * 补充表头缺失数据
 * @param sheet 
 */
const getTableRow = (sheet: Sheet) => {
    const data: any[] = []
    const range = utils.decode_range((sheet['!ref'] as string))
    let C: number
    const R = range.s.r
    /* start in the first row */
    for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
        const cell = sheet[utils.encode_cell({ c: C, r: R })]
        /* find the cell in the first row */
        let hdr = utils.encode_cell({ c: C, r: R }) // <-- replace with your desired default
        if (!cell || !cell.t) {
            sheet[utils.encode_cell({ c: C, r: R })] = {
                h: hdr,
                r: `<td>${hdr}</td>`,
                t: "s",
                v: hdr,
                w: hdr
            }
        }
    }
    return sheet
}

/**
 * 生成表头数据
 * @param sheet 
 */
const getHeaderRow = (sheet: Sheet) => {
    const headers: string[] = []
    const range = utils.decode_range((sheet['!ref'] as string))
    let C: number
    const R = range.s.r
    /* start in the first row */
    for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
        const cell = sheet[utils.encode_cell({ c: C, r: R })]
        /* find the cell in the first row */
        let hdr = utils.encode_cell({ c: C, r: R }) // <-- replace with your desired default
        if (cell && cell.t) hdr = utils.format_cell(cell)
        headers.push(hdr)
    }
    return headers
}

/**
 * 生成数据
 * @param param 
 */
const generateData = ({ header, results }: IGenerateData) => {
    excelData.value.header = header
    excelData.value.results = results
    $props.onSuccess && $props.onSuccess(excelData.value)
}
</script>
<style scoped>
.excel-upload-input {
    display: none;
    z-index: -9999;
}
</style>